package com.mzpai.product.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * 
 * @author li
 * 
 *         2014年11月12日
 *         
 *   * 多线程并发访问服务器
   * 
   * 每次http连接需要三次握手，开销很大，http/1.1默认支持连接复用；
   * 
   * PoolingHttpClientConnectionManager 允许管理器限制最大连接数 ，还允许每个路由器针对某个主机限制最大连接数。
   * 
   * 如下：setDefaultMaxPerRoute(3)之后，每次并发3个访问，所以打印输出是每次输出三个"test",验证了http连接管理器生效；
   * 
   *  清空失效连接：
   * 
   * 	连接的有效性检测是所有连接池都面临的一个通用问题，大部分HTTP服务器为了控制资源开销，并不会
    永久的维护一个长连接，而是一段时间就会关闭该连接。放回连接池的连接，如果在服务器端已经关闭，客
    户端是无法检测到这个状态变化而及时的关闭Socket的。这就造成了线程从连接池中获取的连接不一定是有效的。
    这个问题的一个解决方法就是在每次请求之前检查该连接是否已经存在了过长时间，可能已过期。
    但是这个方法会使得每次请求都增加额外的开销。HTTP Client4.0的ThreadSafeClientConnManager 提供了
    closeExpiredConnections()方法和closeIdleConnections()方法来解决该问题。
    前一个方法是清除连接池中所有过期的连接，至于连接什么时候过期可以设置，设置方法将在下面提到，
    而后一个方法则是关闭一定时间空闲的连接，可以使用一个单独的线程完成这个工作。
 */
public class HttpClient {
	private static Logger log = LoggerFactory.getLogger(HttpClient.class);
	private static final int REQUEST_TIMEOUT = 60 * 1000;// 设置请求超时20秒钟
	private static final int SO_TIMEOUT = 60 * 1000; // 设置等待数据超时时间20秒钟
    public static final int HTTP_MAX_CONNECTIONS = 200;
	private static RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(SO_TIMEOUT).setConnectTimeout(REQUEST_TIMEOUT).build();//设置请求和传输超时时间
	private static CloseableHttpClient client;
	
	public static String doPost(String url) throws ClientProtocolException, IOException {
		
		HttpPost httpPost = new HttpPost(url);
		httpPost.setConfig(requestConfig);
		CloseableHttpResponse response = null;
		HttpEntity entity = null;
		try {
			response = client.execute(httpPost);
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				entity = response.getEntity();
				String returnStr = EntityUtils.toString(entity, "utf-8");
				return returnStr;
			}
		}catch (Exception e) {
			log.error(e.getMessage(), e);
		}finally{
			EntityUtils.consume(entity);
			httpPost.abort();
			if(response!=null){
				response.close();
			}
		}
		
		return null;
	}

	public static String doPost(String url, Map<String, Object> params) throws IOException {
	
//		log.info("params="+params.toString());
		
		HttpPost httpPost = new HttpPost(url);
		httpPost.setConfig(requestConfig);
		CloseableHttpResponse response = null;
		HttpEntity entity = null;
		try {
//			httpPost.addHeader("Host", new URI(url).getHost());
			
		    List <NameValuePair> nameValuePair = new ArrayList<NameValuePair>();
			if (params != null && !params.isEmpty()) {
				for (String key : params.keySet()) {
					nameValuePair.add(new BasicNameValuePair(key, params.get(key).toString()));
				}
			}
		    httpPost.setEntity(new UrlEncodedFormEntity(nameValuePair, "utf-8"));
			response = client.execute(httpPost);
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				entity = response.getEntity();
				String returnStr = EntityUtils.toString(entity, "utf-8");
				return returnStr;
			}else{
				log.error("url="+url+",params="+params+",getStatusCode="+response.getStatusLine().getStatusCode());
			}
		}catch (Exception e) {
			log.error(e.getMessage(), e);
		}finally{
		
			EntityUtils.consume(entity);
			httpPost.abort();
			if(response!=null){
				response.close();
			}
			
		}
		
		return null;
	}
	
	public static String doPostForTeLaiDian(String url, String params,String token) throws IOException {
		
//		log.info("params="+params.toString());
		
		HttpPost httpPost = new HttpPost(url);
		httpPost.setConfig(requestConfig);
		CloseableHttpResponse response = null;
		HttpEntity entity = null;
		try {
			httpPost.addHeader("Authorization","Bearer " + token);//Bearer后有空格
		    httpPost.setEntity(new StringEntity(params, "utf-8"));
		    
		    long startTime = System.currentTimeMillis();
			response = client.execute(httpPost);
			long endTime = System.currentTimeMillis();
			long t = endTime - startTime;
			log.info("url="+url+" 耗时 过长： " + t  + "毫秒");
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				entity = response.getEntity();
				String returnStr = EntityUtils.toString(entity, "utf-8");
				return returnStr;
			}else{
				log.error("url="+url+",params="+params+",getStatusCode="+response.getStatusLine().getStatusCode());
			}
		}catch (Exception e) {
			log.error(e.getMessage(), e);
		}finally{
		
			EntityUtils.consume(entity);
			httpPost.abort();
			if(response!=null){
				response.close();
			}
			
		}
		
		return null;
	}

    public static String doPostForCDDZ(String url, String params,String token) throws IOException {

//		log.info("params="+params.toString());

        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        CloseableHttpResponse response = null;
        HttpEntity entity = null;
        try {
            httpPost.addHeader("Authorization","Bearer " + token);//Bearer后有空格
            httpPost.setEntity(new StringEntity(params, "utf-8"));

            long startTime = System.currentTimeMillis();
            response = client.execute(httpPost);
            long endTime = System.currentTimeMillis();
            long t = endTime - startTime;
			log.info("url="+url+" 耗时 过长： " + t  + "毫秒");
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK
                    || response.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED) {
                entity = response.getEntity();
                String returnStr = EntityUtils.toString(entity, "utf-8");
                return returnStr;
            }else{
                log.error("url="+url+",params="+params+",getStatusCode="+response.getStatusLine().getStatusCode());
                entity = response.getEntity();
                String returnStr = EntityUtils.toString(entity, "utf-8");
                System.out.println(returnStr);
            }
        }catch (Exception e) {
            log.error(e.getMessage(), e);
        }finally{

            EntityUtils.consume(entity);
            httpPost.abort();
            if(response!=null){
                response.close();
            }

        }

        return null;
    }
	/**
	 * 上传图片
	 * @param url
	 * @param file
	 * @param params
	 * @return
	 * @throws IOException
	 */
	public static String uploadFile(String url, File file ,Map<String, Object> params) throws IOException {
		log.info("url="+url);
		log.info("params="+params.toString());
		
		HttpPost httpPost = new HttpPost(url);
		httpPost.setConfig(requestConfig);
		CloseableHttpResponse response = null;
		HttpEntity entity = null;
		FileBody bin = null;
		if (file != null) {
			bin = new FileBody(file);
		}
		try {
			httpPost.addHeader("Authorization", "uploadFile");
		    MultipartEntityBuilder reqEntity = MultipartEntityBuilder.create();
		    reqEntity.addPart("file", bin);
		        
			if (params != null && !params.isEmpty()) {
				for (String key : params.keySet()) {
					StringBody comment = new StringBody(params.get(key).toString(), ContentType.TEXT_PLAIN);
					reqEntity.addPart(key, comment);
				}
			}
		    httpPost.setEntity(reqEntity.build());
		    
			response = client.execute(httpPost);
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				entity = response.getEntity();
				String returnStr = EntityUtils.toString(entity, "utf-8");
				return returnStr;
			}else{
				log.error("getStatusCode="+response.getStatusLine().getStatusCode());
			}
		}catch (Exception e) {
			log.error(e.getMessage(), e);
		}finally{
		
			EntityUtils.consume(entity);
//			httpPost.abort();
			if(response!=null){
				response.close();
			}
			
		}
		
		return null;
	}
	
	/**
	 * 项目间调用
	 * @param url
	 * @param userToken
	 * @param params
	 * @return
	 * @throws IOException
	 */
	public static String doPost(String url, String userToken,Map<String, Object> params) throws IOException {
		log.info("url="+url);
		log.info("params="+params.toString());
		
		HttpPost httpPost = new HttpPost(url);
		httpPost.setConfig(requestConfig);
		CloseableHttpResponse response = null;
		HttpEntity entity = null;
	
		try {
			httpPost.addHeader("Authorization", userToken);
		    MultipartEntityBuilder reqEntity = MultipartEntityBuilder.create();
		        
			if (params != null && !params.isEmpty()) {
				for (String key : params.keySet()) {
					StringBody comment = new StringBody(params.get(key).toString(), ContentType.TEXT_PLAIN);
					reqEntity.addPart(key, comment);
				}
			}
		    httpPost.setEntity(reqEntity.build());
		    
			response = client.execute(httpPost);
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				entity = response.getEntity();
				String returnStr = EntityUtils.toString(entity, "utf-8");
				return returnStr;
			}else{
				log.error("getStatusCode="+response.getStatusLine().getStatusCode());
			}
		}catch (Exception e) {
			log.error(e.getMessage(), e);
		}finally{
		
			EntityUtils.consume(entity);
			httpPost.abort();
			if(response!=null){
				response.close();
			}
			
		}
		
		return null;
	}
	
	
	public static String doGet(String url) throws IOException {

		HttpGet httpGet = new HttpGet(url);
		httpGet.setConfig(requestConfig);
		CloseableHttpResponse response = null;
		HttpEntity entity = null;
		try {
			response = client.execute(httpGet);
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				entity = response.getEntity();
				String returnStr = EntityUtils.toString(entity, "utf-8");
				EntityUtils.consume(entity);
				return returnStr;
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}finally{
			EntityUtils.consume(entity);
//			httpGet.abort();
			if(response!=null){
				response.close();
			}
		}

		return null;
	}
	
	

	public static String doGet(String url,Map<String, Object> parametersMap) throws ClientProtocolException, IOException {
		
		if (parametersMap!=null){
			StringBuffer parameters = new StringBuffer();
			int i = 0;
			for (String key : parametersMap.keySet()) {
				if (i == 0){
					parameters.append("?");
				}else{
					parameters.append("&");
				}
				parameters.append(key);
				parameters.append("=");
				parameters.append(encoding(parametersMap.get(key).toString(),"UTF-8"));
				i++;
			}
			url = url + parameters.toString();
		}
//		log.info("url="+url);
		HttpGet httpGet = new HttpGet(url);
		httpGet.setConfig(requestConfig);
		HttpEntity entity = null;
		try {
			CloseableHttpResponse response = client.execute(httpGet);
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				entity = response.getEntity();
				String returnStr = EntityUtils.toString(entity, "utf-8");
				return returnStr;
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}finally{
			EntityUtils.consume(entity);
//			httpGet.abort();
		}
	
		return null;
	}
	
	/**
	 * 发送xml
	 * @param url
	 * @param xml
	 * @return
	 */
	public static String postXML(String url,String xml){
        CloseableHttpClient client = null;
        CloseableHttpResponse resp = null;
        try{
            HttpPost httpPost = new HttpPost(url);
            httpPost.setHeader("Content-Type", "text/xml; charset=UTF-8");
            client = HttpClients.createDefault();
            StringEntity entityParams = new StringEntity(xml,"utf-8");
            httpPost.setEntity(entityParams);
            client = HttpClients.createDefault();
            resp = client.execute(httpPost);
            String resultMsg = EntityUtils.toString(resp.getEntity(),"utf-8");
            return resultMsg;
        }catch (Exception e){
           log.info("异常={}", e);
        }finally {
            try {
                if(client!=null){
                    client.close();
                }
                if(resp != null){
                    resp.close();
                }
            } catch (IOException e) {
            	log.info("异常={}", e);
            }
        }
        return null;
    }
	


	public static String convertStreamToString(InputStream is) {
		BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		StringBuilder sb = new StringBuilder();
		String line = null;
		try {
			while ((line = reader.readLine()) != null) {
				sb.append(line);
			}
		} catch (IOException e) {
			log.error(e.getMessage(), e);
		} finally {
			try {
				is.close();
			} catch (IOException e) {
				log.error(e.getMessage(), e);
			}
		}

		return sb.toString();

	}

	private static String encoding(String content, String encoding) {
		if (content != null) {
			try {
				content = URLEncoder.encode(content, encoding);
			} catch (UnsupportedEncodingException e) {
				log.error(e.getMessage(), e);
			}
		}
		return content;
	}

	/**
	 * 去掉url中的路径，留下请求参数部分
	 * 
	 * @param strURL
	 *            url地址
	 * @return url请求参数部分
	 */
	private static String TruncateUrlPage(String strURL) {
		String strAllParam = null;
		String[] arrSplit = null;

		strURL = strURL.trim();

		arrSplit = strURL.split("[?]");
		if (strURL.length() > 1) {
			if (arrSplit.length > 1) {
				if (arrSplit[1] != null) {
					strAllParam = arrSplit[1];
				}
			}
		}

		return strAllParam;
	}

	/**
	 * 解析出url参数中的键值对 如 "index.jsp?Action=del&id=123"，解析出Action:del,id:123存入map中
	 * 
	 * @param URL
	 *            url地址
	 * @return url请求参数部分
	 */
	public static Map<String, String> urlRequest(String URL) {
		Map<String, String> mapRequest = new HashMap<String, String>();

		String[] arrSplit = null;

		String strUrlParam = TruncateUrlPage(URL);
		if (strUrlParam == null) {
			return mapRequest;
		}
		// 每个键值为一组
		arrSplit = strUrlParam.split("[&]");
		for (String strSplit : arrSplit) {
			String[] arrSplitEqual = null;
			arrSplitEqual = strSplit.split("[=]");

			// 解析出键值
			if (arrSplitEqual.length > 1) {
				// 正确解析
				mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);

			} else {
				if (!arrSplitEqual[0].equals("")) {
					// 只有参数没有值，不加入
					mapRequest.put(arrSplitEqual[0], "");
				}
			}
		}
		return mapRequest;
	}
	
}
